#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "SDS.h"

/**
 * 创建sds
 */
sds sds_create(const void *init, const size_t init_len) {
    sdshdr *sh = malloc(sizeof(sdshdr) + init_len + 1);
    memcpy(sh->buf, init, init_len);
    sh->len           = init_len;
    sh->free          = 0;
    sh->buf[init_len] = '\0';
    return sh->buf;
}

/**
 * 创建一个空sds
 * @param len 分配给sds的空间大小(不用不包括'\0')
 */
sds sds_create_empty(const size_t len) {
    sdshdr *sh = malloc(sizeof(sdshdr) + len + 1);
    sh->len    = 0;
    sh->free   = len;
    sh->buf[0] = '\0';
    return sh->buf;
}

sds sds_new(const char *str) { return sds_create(str, strlen(str)); }

sds sds_dup(const sds s) { return sds_create(s, sds_len(s)); }

/**
 * 修改sds
 */
sds sds_update(sds old_s, const void *new_s, const size_t len) {
    sdshdr *sh = (sdshdr *) (old_s - sizeof(sdshdr));
    if (sh->len >= len) {
        memcpy(sh->buf, new_s, len);
        sh->buf[len] = '\0';
        sh->free     = sh->free - sh->len + len;
        sh->len      = len;
    } else {
        /*
         * 修改后的sds大于原先的sds长度, 则需“考虑”内存是否足够。
         */
        int capcity = sh->free + sh->len;
        if (capcity < len) {
            free(sh);
            capcity = len * 2;
            sh      = malloc(sizeof(sdshdr) + capcity + 1);
        }
        sh->len  = len;
        sh->free = capcity - sh->len;
        memcpy(sh->buf, new_s, len);
        sh->buf[len] = '\0';
    }
    return sh->buf;
}

sds sds_cat(sds s, const char *t) { return sds_cat_len(s, t, strlen(t)); }

sds sds_cat_len(sds s, const void *t, size_t len) {
    // 确保空间足够
    s = sds_make_room(s, len);
    if (s == NULL)
        return NULL;

    // 拷贝字符串
    memcpy(s + sds_len(s), t, len);

    // 更新sds属性
    sds_incr_len(s, len);

    return s;
}

sds sds_cat_printf(sds s, const char *t, ...) {
    va_list args;
    va_start(args, t); // 初始化参数列表

    va_list ap_copy;
    va_copy(ap_copy, args); // 复制参数列表，因为vsnprintf会修改它

    // 计算需要追加的字符串长度
    int len = vsnprintf(NULL, 0, t, ap_copy);
    va_end(ap_copy); // 清理复制的参数列表

    if (len < 0)
        return NULL; // 格式化错误

    // 确保空间足够
    s = sds_make_room(s, len);
    if (s == NULL)
        return NULL;

    // 格式化字符串并追加到sds字符串的末尾
    int n = vsnprintf(s + sds_len(s), len + 1, t, args);
    if (n < 0)
        return NULL; // 格式化错误

    // 更新sds属性
    sds_incr_len(s, n);

    return s;
}

/**
 * 删除字符串中的其中一段 [start, end]
 */
void sds_delete_range(sds s, const int start, const int end) {
    sdshdr *sh  = (sdshdr *) (s - sizeof(sdshdr));
    size_t  len = sh->len;
    // if (len == 0) return;
    // if (start < 0 || start >= len) return;
    // if (end < 0 || end >= len) return;
    // if (start > end) return;
    memmove(sh->buf + start, sh->buf + end + 1, len - end - 1);
    size_t range_len = end - start + 1;
    sds_incr_len(s, -range_len);
}

sds sds_get_range(sds s, const int start, const int end) {
    sdshdr *sh = (sdshdr *) (s - sizeof(sdshdr));
    return sds_create(sh->buf + start, end - start + 1);
}

char *sds_get_str(sds s) {
    char *str = malloc(sds_len(s) + 1);
    memcpy(str, s, sds_len(s));
    str[sds_len(s)] = '\0';
    return str;
}

char *sds_get_str_range(sds s, const int start, const int end) {
    char *str = malloc(end - start + 2);
    memcpy(str, s + start, end - start + 1);
    str[end - start + 1] = '\0';
    return str;
}

int sds_index_of(sds s, const char c) {
    for (int i = 0; i < sds_len(s); i++) {
        if (s[i] == c) {
            return i;
        }
    }
    return -1;
}

int sds_index_of_start(sds s, int start, const char c) {
    for (int i = start; i < sds_len(s); i++) {
        if (s[i] == c) {
            return i;
        }
    }
    return -1;
}

int sds_index_last_of(sds s, const char c) {
    for (int i = sds_len(s) - 1; i >= 0; i--) {
        if (s[i] == c) {
            return i;
        }
    }
    return -1;
}

/**
 * 分割字符串
 * 仅支持单字节分隔符
 */
sds *sds_split(const char *s, const int len, const char *sep, const int sep_len, int *count) {
    *count = 0;
    if (len == 0) {
        return NULL;
    }
    int  elements = 0, start = 0, init_capacity = 1;
    sds *tokens = malloc(sizeof(sds) * init_capacity);

    for (int i = 0; i < len; i++) {
        if (s[i] == *sep) {
            if (i != start) {
                if (elements == init_capacity) {
                    init_capacity += 1;
                    tokens = realloc(tokens, sizeof(sds) * init_capacity);
                }
                tokens[elements] = sds_create(s + start, i - start);
                elements++;
            }
            start = i + 1;
        }
    }
    if (start != len) {
        tokens[elements] = sds_create(s + start, len - start);
        elements++;
    }
    *count = elements;

    if (elements == 0) {
        free(tokens);
        return NULL;
    }

    return tokens;
}

/**
 * 用于释放sds_split返回的数组
 */
void sds_free_split(sds *tokens, int count) {
    while (count--) {
        sds_free(tokens[count]);
    }
    free(tokens);
}

/**
 * 比较两个sds的大小。
 * 若大于则返回正数,
 * 若小于则返回负数,
 * 若等于则返回0。
 */
int sds_compare(const sds a, const sds b) {
    size_t a_len   = sds_len(a);
    size_t b_len   = sds_len(b);
    size_t min_len = (a_len > b_len) ? b_len : a_len;
    for (size_t i = 0; i < min_len; i++) {
        if (a[i] > b[i]) {
            return 1;
        }
        if (a[i] < b[i]) {
            return -1;
        }
    }
    return a_len - b_len;
}

/**
 * 将sds转为普通字符串
 */
char *sds_to_str(sds s) {
    char *str = malloc(sizeof(char) * (sds_len(s) + 1));
    memcpy(str, s, sds_len(s));
    str[sds_len(s)] = '\0';
    sds_free(s);

    return str;
}

/**
 * 将sds转为普通字符串, 并截取
 */
char *sds_to_str_range(sds s, const int start, const int end) {
    char *str = malloc(sizeof(char) * (end - start + 2));
    memcpy(str, s + start, end - start + 1);
    str[end - start + 1] = '\0';
    sds_free(s);

    return str;
}

/**
 * 将sds中的字符转为小写
 */
void sds_to_lower(sds s) {
    for (int i = 0; i < sds_len(s); i++) {
        s[i] = tolower(s[i]);
    }
}

/**
 * 将sds中的字符转为大写
 */
void sds_to_upper(sds s) {
    for (int i = 0; i < sds_len(s); i++) {
        s[i] = toupper(s[i]);
    }
}

/**
 * 主要用于sds读取完数据后, 修改len和free属性
 */
void sds_incr_len(const sds s, const int incr) {
    sdshdr *sh = (sdshdr *) (s - sizeof(sdshdr));
    sh->len += incr;
    sh->free -= incr;
    s[sh->len] = '\0';
}

/**
 * 只修改len属性和free属性, 但不修改 \0 的位置
 */
void sds_update_len(const sds s, const int new_len) {
    sdshdr *sh = (sdshdr *) (s - sizeof(sdshdr));
    sh->free += sh->len - new_len;
    sh->len = new_len;
}

/**
 * 根据要写入的数据长度判断是否需要扩容
 * 若需要则进行扩容
 */
sds sds_make_room(sds s, const int read_len) {
    // 剩余空间足够写入
    if (sds_free_len(s) >= read_len)
        return s;

    int old_len = sds_len(s);
    int new_len = old_len + read_len;

    // 分配新空间
    sdshdr *sh     = (sdshdr *) (s - sizeof(sdshdr));
    sdshdr *new_sh = realloc(sh, sizeof(sdshdr) + new_len + 1);
    if (new_sh == NULL)
        return NULL;

    new_sh->free = new_len - old_len;

    return new_sh->buf;
}

/**
 * 清空sds
 */
void sds_clear(const sds s) {
    sdshdr *sh = (sdshdr *) (s - sizeof(sdshdr));
    sh->free += sh->len;
    sh->len    = 0;
    sh->buf[0] = '\0';
}

/**
 * 释放sds内存
 */
void sds_free(const sds s) {
    sdshdr *sh = (sdshdr *) (s - sizeof(sdshdr));
    free(sh);
}

/**
 * 获取sds长度
 */
int sds_len(const sds s) {
    sdshdr* sh = (sdshdr*) (s - sizeof(sdshdr));
    return sh->len;
}

/**
 * 获取sds空闲长度
 */
int sds_free_len(const sds s) {
    sdshdr* sh = (sdshdr*) (s - sizeof(sdshdr));
    return sh->free;
}

/**
 * 判断sds是否为空
 */
int sds_is_empty(const sds s) {
    return sds_len(s) == 0;
}